package com.guohong.service.impl;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.guohong.constant.MaodouConstant;
import com.guohong.dto.LoginDto;
import com.guohong.dto.MenuDto;
import com.guohong.dto.RoleOptionDto;
import com.guohong.dto.UserDto;
import com.guohong.dto.UserPageDto;
import com.guohong.entity.Menu;
import com.guohong.entity.User;
import com.guohong.exception.ServiceException;
import com.guohong.jwt.JWTUtil;
import com.guohong.mapper.MenuMapper;
import com.guohong.mapper.PermissionMapper;
import com.guohong.mapper.UserMapper;
import com.guohong.mapper.UserRoleMapper;
import com.guohong.router.RouterMeta;
import com.guohong.router.VueRouter;
import com.guohong.service.UserRoleService;
import com.guohong.service.UserService;
import com.guohong.util.DateUtil;
import com.guohong.vo.UserAddVo;
import com.guohong.vo.UserDeleteVo;
import com.guohong.vo.UserEditVo;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

@Service
public class UserServiceImpl implements UserService {
	private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Autowired
	private UserMapper userMapper;
	@Autowired
	private MenuMapper menuMapper;
	@Autowired
	private PermissionMapper permissionMapper;
	@Value("${jwtTimeOut}")
	private int jwtTimeOut;
	@Autowired
	private UserRoleMapper userRoleMapper;
	@Autowired
	private UserRoleService userRoleService;
//	@Autowired
//	private JedisPool jedisPool;

	@Override
	public User selectByPrimaryKey(Long id) {
		return userMapper.selectByPrimaryKey(id);
	}

	@Transactional(readOnly = true)
	@Override
	public UserPageDto listUsersByPage(String username, int pageNum, int pageSize) {
		PageHelper.startPage(pageNum, pageSize);
		Page<User> users = userMapper.listUsersByPage(username);

		List<UserDto> userDtos = null;
		UserPageDto userPageDto = null;

		if (!CollectionUtils.isEmpty(users)) {
			userDtos = new ArrayList<UserDto>();
			userPageDto = new UserPageDto();

			for (User user : users) {
				UserDto userDto = new UserDto();
				BeanUtils.copyProperties(user, userDto, "createTime", "updateTime");

				if (null != user.getCreateTime()) {
					userDto.setCreateTime(formatter.format(user.getCreateTime()));
				}
				if (null != user.getUpdateTime()) {
					userDto.setUpdateTime(formatter.format(user.getUpdateTime()));
				}

				List<RoleOptionDto> roleOptionDtos = userRoleMapper.getRoleOptionsByUserId(user.getId());
				userDto.setRoleOptions(roleOptionDtos);

				userDtos.add(userDto);
			}

			userPageDto.setTotal(users.getTotal());
			userPageDto.setUsers(userDtos);
		}

		return userPageDto;
	}

	private boolean authentication(String username, String hashedPassword) throws Exception {
		User user = userMapper.getByUsername(username);
		if (null != user) {
			if (hashedPassword.equals(user.getPassword())) {
				return true;
			}
		} else {
			throw new ServiceException("501", "用户名或者密码不正确");
		}
		return false;
	}

	/**
	 * sha512加密算法进行加密
	 * 
	 * @param password
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	private String sha512enctypt(String password) throws NoSuchAlgorithmException {
		MessageDigest md = MessageDigest.getInstance("SHA-512");
		byte[] bytes = md.digest(password.getBytes(StandardCharsets.UTF_8));
		// String hashedPassword = new String(bytes,StandardCharsets.UTF_8);

		String hashedPassword = Base64.getEncoder().encodeToString(bytes);
		return hashedPassword;
	}

	@Transactional(readOnly = true)
	@Override
	public LoginDto login(String username, String password) throws Exception {
		LoginDto loginDto = null;

		String hashedPassword = sha512enctypt(password);

		if (authentication(username, hashedPassword)) { // 认证成功
			User user = userMapper.getByUsername(username);

			loginDto = new LoginDto();
			UserDto userInfo = new UserDto();
			BeanUtils.copyProperties(user, userInfo);
			loginDto.setUserInfo(userInfo);

			loginDto.setPermissions(permissionMapper.getUserPermissions(user.getId()));

			// loginDto.setRouters(getVueRouters(user.getId()));

			Date expireTime = getExpireTime();

			String token = JWTUtil.sign(username, hashedPassword, expireTime);
			String expireTimeStr = DateUtil.formatFullTime(expireTime);

//			saveUserInfoToRedis(userInfo);

			loginDto.setToken(token);
			loginDto.setExipreTime(expireTimeStr);

		} else {
			throw new ServiceException("501", "用户名或者密码不正确");
		}

		return loginDto;
	}

	private Date getExpireTime() {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date());
		calendar.add(Calendar.SECOND, jwtTimeOut);
		Date expireTime = calendar.getTime();
		return expireTime;
	}

	/*private void saveUserInfoToRedis(UserDto userInfo) {
		String userInfoStr = JSON.toJSONString(userInfo);

		try (Jedis jedis = jedisPool.getResource()) {
			jedis.set(MaodouConstant.CURRENT_USER_PREFIX + userInfo.getUsername(), userInfoStr);

		} catch (Exception e) {
			// TODO: handle exception
			// logger
		}
	}*/
	
	// ======
	// TODO
	@Override
	public List<MenuDto> getUserMenuTree(Long userId) {
		MenuDto ROOT = new MenuDto();
		ROOT.setId(MaodouConstant.MENU_ROOT_ID);

		recursion(ROOT, userId);
		return ROOT.getChildren();
	}

	private void recursion(MenuDto parentMenu, Long userId) {
		List<Menu> subMenus = getSubMenus(parentMenu.getId(), userId);
		if (!CollectionUtils.isEmpty(subMenus)) { // 有子菜单
			List<MenuDto> children = new ArrayList<>();

			for (Menu menu : subMenus) {
				MenuDto menuDto = new MenuDto();
				BeanUtils.copyProperties(menu, menuDto);
				children.add(menuDto);

				recursion(menuDto, userId);
			}

			parentMenu.setChildren(children);
		}
	}

	private List<Menu> getSubMenus(Long parentId, Long userId) {
		Map<String, Object> params = new HashMap<>();
		params.put("parentId", parentId);
		params.put("userId", userId);

		return menuMapper.getUserSubMenus(params);
	}

	// ======

	@Override
	public List<VueRouter> getVueRouters(Long userId) {
		VueRouter ROOT = new VueRouter();
		ROOT.setId(MaodouConstant.MENU_ROOT_ID);

		recursion(ROOT, userId);
		return ROOT.getChildren();
	}

	private void recursion(VueRouter parentRouter, Long userId) {
		List<Menu> subMenus = getSubMenus(parentRouter.getId(), userId);

		if (!CollectionUtils.isEmpty(subMenus)) { // 有子菜单
			List<VueRouter> children = new ArrayList<>();

			for (Menu menu : subMenus) {
				VueRouter vueRouter = new VueRouter();
				RouterMeta meta = new RouterMeta();

				BeanUtils.copyProperties(menu, vueRouter);
				meta.setTitle(menu.getName());
				meta.setIcon(menu.getIcon());
				vueRouter.setMeta(meta);

				children.add(vueRouter);
				recursion(vueRouter, userId);
			}

			parentRouter.setChildren(children);
		} else {
			parentRouter.setAlwaysShow(false);
		}
	}

	@Transactional
	@Override
	public int insert(UserAddVo addUserVo) throws Exception {
		User user = new User();
		BeanUtils.copyProperties(addUserVo, user);
		
		String username = JWTUtil.getUsername(addUserVo.getToken());
		UserDto userInfo = null;
		
		/*try(Jedis jedis = jedisPool.getResource()) {
			String userInfoStr = jedis.get(MaodouConstant.CURRENT_USER_PREFIX+username);
			userInfo = JSON.parseObject(userInfoStr, UserDto.class);
		} catch (Exception e) {
			// TODO: handle exception
		}*/
		
		// TODO,如何获取当前登录用户
		user.setCreateUser(userInfo.getUsername());
		user.setCreateTime(new Date());

		MessageDigest md = MessageDigest.getInstance("SHA-512");
		byte[] bytes = md.digest(addUserVo.getPassword().getBytes(StandardCharsets.UTF_8));
		String hashedPassword = Base64.getEncoder().encodeToString(bytes);

		// 密文
		user.setPassword(hashedPassword);

		int result = userMapper.insert(user);
		userRoleService.saveOrUpdate(user.getId(), addUserVo.getRoleIds());

		return result;
	}

	@Transactional
	@Override
	public int update(UserEditVo userEditVo) throws Exception {
		User user = userMapper.selectByPrimaryKey(userEditVo.getId());

		BeanUtils.copyProperties(userEditVo, user, "id", "username");
		userRoleService.saveOrUpdate(user.getId(), userEditVo.getRoleIds());

		return userMapper.updateByPrimaryKey(user);
	}

	@Override
	public void deleteUsers(UserDeleteVo userDeleteVo) {
		if (StringUtils.isNotBlank(userDeleteVo.getIds())) {
			String[] arr = userDeleteVo.getIds().split(",");

			List<Long> ids = new ArrayList<>();
			for (String str : arr) {
				ids.add(Long.valueOf(str));
			}

			userMapper.deleteUsers(ids);
		}
	}

}
